/*
 *    	@(#)PopulateInterceptor.java  2008-11-19
 *      
 *      @COPYRIGHT@
 */
package com.capinfo.framework.interceptor;

import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.Iterator;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.EmptyInterceptor;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.type.Type;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import com.capinfo.accumulation.model.HadSiteEntity;
import com.capinfo.accumulation.web.Constants;
import com.capinfo.framework.annotation.LazyInject;
import com.capinfo.framework.model.BaseEntity;
import com.capinfo.framework.model.HadMultipleEntity;
import com.capinfo.framework.model.MultipleEntity;
import com.capinfo.framework.util.PropertyUtils;

/**
 * <p>
 * 对需要通过Hibernate进行持久、加载的对象进行拦截。
 * 这里主要是用来自动组装多选项（com.capinfo.framework.model.MultipleEntity）的数据。
 * </p>
 * 
 * @version 1.0
 * @author 张名扬
 * 
 */

public class PopulateInterceptor<T extends BaseEntity> extends EmptyInterceptor implements ApplicationContextAware{
	
	private static final Log logger = LogFactory.getLog(PopulateInterceptor.class);

	private SessionFactory sessionFactory;
	
	private String sessionFactoryBeanId = "sessionFactory4Ecomm";
	
	private ApplicationContext context;//声明一个静态变量保存
	
	@Override
	public void setApplicationContext(ApplicationContext contex) throws BeansException {

		this.context=contex;
	}

	public SessionFactory getSessionFactory() {
		if( null == sessionFactory ){
			sessionFactory = (SessionFactory)context.getBean(sessionFactoryBeanId);
		}
		return sessionFactory;
	}

	@LazyInject(beanId="sessionFactory4Ecomm")
	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	public String getSessionFactoryBeanId() {
		return sessionFactoryBeanId;
	}

	public void setSessionFactoryBeanId(String sessionFactoryBeanId) {
		this.sessionFactoryBeanId = sessionFactoryBeanId;
	}

	/**
	 * <p>
	 * 每次加载对象时，自动给多选的属性组装上数据。
	 * </p>
	 */
	public boolean onLoad(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
		//System.out.println("preLoad");
		//System.out.println(sessionFactory);
		if( entity instanceof HadMultipleEntity ) {

			MultipleEntity<T>[] multipleProperties = ((HadMultipleEntity) entity).getMultipleProperties();
			
			for(int i = 0, num = multipleProperties.length; i < num; i++) {
				
				MultipleEntity<T> multipleEntity = multipleProperties[i];

				int index = getIndex(propertyNames, multipleEntity.getHandleName());
				if( -1 != index ) {
					
					populateMultipleEntity(multipleEntity
											, (String) state[index]);
				}
			}
		}
		
		return true;
	}

	/**
	 * <p>
	 * 每次持久化数据的时候，自动将多选属性的值放入相应的持久化属性，进行持久化。
	 * </p>
	 */
	public void preFlush(Iterator entities) {

		//System.out.println("preFlush");
		while( entities.hasNext() ) {

			Object entity = entities.next();
			//System.out.println("entity ==>" + entity);
			if( entity instanceof HadMultipleEntity ) {

				MultipleEntity<T>[] multipleProperties = ((HadMultipleEntity) entity).getMultipleProperties();
				//System.out.println("multipleProperties ==>" + Arrays.asList(multipleProperties));
				for(int i = 0, num = multipleProperties.length; i < num; i++) {
					
					MultipleEntity<T> multipleEntity = multipleProperties[i];
					
					//System.out.println("state[index] => " + multipleEntity.getIdString());
					PropertyUtils.setProperty(entity, multipleEntity.getHandleName(), multipleEntity.getIdString());
				}
			}
			
			if( entity instanceof HadSiteEntity ) {
				
				HadSiteEntity hadSiteEntity = (HadSiteEntity) entity;
				
				hadSiteEntity.setSiteId(Constants.THREAD_LOCAL_DATA_SCOPE_ID.get());
			}
		}
	}

	/**
	 * <p>
	 * 每次持久化数据的时候，自动将多选属性的值放入相应的持久化属性，进行持久化。
	 * </p>
	 */
	public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {

		//System.out.println("state[index] => ");
		if( entity instanceof HadMultipleEntity ) {

			MultipleEntity<T>[] multipleProperties = ((HadMultipleEntity) entity).getMultipleProperties();
			
			for(int i = 0, num = multipleProperties.length; i < num; i++) {
				
				MultipleEntity<T> multipleEntity = multipleProperties[i];
				
				int index = getIndex(propertyNames, multipleEntity.getHandleName());
				//System.out.println("state[index] => " + state[index]);
				//System.out.println("state[index] => " + multipleEntity.getIdString());
				state[index] = multipleEntity.getIdString();
				//System.out.println("state[index] => " + state[index]);
				PropertyUtils.setProperty(entity, multipleEntity.getHandleName(), state[index]);
				
				populateMultipleEntity(multipleEntity, multipleEntity.getIdString());
			}
		}
		
		if( entity instanceof HadSiteEntity ) {
			
			HadSiteEntity hadSiteEntity = (HadSiteEntity) entity;
			
			hadSiteEntity.setSiteId(Constants.THREAD_LOCAL_DATA_SCOPE_ID.get());
		}
		
		return true;
	}
	
	private int getIndex(String[] propertyNames, String propertyName) {
		
		for(int i = 0, num = propertyNames.length; i < num; i++) {
			
			if( propertyNames[i].equals(propertyName) ) {
				
				return i;
			}
		}
		return -1;
	}
	
	private void populateMultipleEntity(MultipleEntity<T> multipleEntity,
			String idStr) {

		if (StringUtils.isNotBlank(idStr)) {
			
			multipleEntity.setIdString(idStr);

			Serializable[] idArray = multipleEntity.getIdArray();
			int jNum = idArray.length;
			
			
			multipleEntity.getEntityArray();
			T[] entityArray = (T[]) Array.newInstance(multipleEntity.getEntityType(), jNum);

			Session session = getSessionFactory().getCurrentSession();
			//session.setFlushMode(FlushMode.MANUAL);

			for (int i = 0; i < jNum; i++) {
				
				entityArray[i] = session.get(multipleEntity.getEntityType(), idArray[i]);
			}
			//session.flush();

			multipleEntity.setEntityArray(entityArray);
			/*synchronized (session) {

				FlushMode flushMode = session.getFlushMode();
				session.setFlushMode(FlushMode.MANUAL);
				
				for (int i = 0; i < jNum; i++) {
					
					Object entity = session.get(multipleEntity.getEntityType()
											, idArray[i]);
					
					entityArray[i] = entity;
				}
				session.setFlushMode(flushMode);

				multipleEntity.setEntityArray(entityArray);
			}*/
		}
	}

}
